不知道大家有沒有這樣的經驗:在排版時無論 z-index
怎麼調整,元素仍然被其他東西蓋住,怎麼調都調不好;今天我們將會深入理解這背後的原因,一起來聊聊 z-index
及與它相關的 堆疊環境(Stacking Context)。
本系列文已經重新編校彙整編輯成冊,並正式出版囉!
《前端三十:從 HTML 到瀏覽器渲染的前端開發者必備心法》好評販售中!
喜歡我文章內容的讀者們,歡迎您 前往購買 支持!
相信這個 CSS 屬性大家應該都不陌生,是用來指定元素在 z 軸的「高度」(越大越靠近使用者);在 CSS2.1 的規格 中指明:
For a positioned box, the 'z-index' property specifies:
- The stack level of the box in the current stacking context.
- Whether the box establishes a stacking context.
這邊的 positioned box 指的是 position
屬性不為預設值(static
)的元素(box 指盒模型);所以 z-index
即為指定元素在 堆疊環境 中的 堆疊層級,且它只在 positioned box 上生效。
眼尖的同學應該已經注意到了,又出現了 昨天文章 就已經提到過的 Stacking Context,那麼它究竟是什麼呢?
在網頁排版時,預設的元素排列會是由上到下、由左到右的依序排列;開發者如果想要調整或固定特定元素的位置,會透過設定 position
為 relative
、absolute
、fixed
,讓指定的元素可以從原本的排列位置移動,甚至離開(Out of Flow)。而這時,也就產生了一個新的 CSS 堆疊環境,從此這個元素及它的子元素,就自成一國,他們的排列也就與其他的堆疊環境無關了。
那這些自成一國的堆疊環境,對開發者來說有什麼影響呢?
很簡單!堆疊環境內的元素、屬性變動,是不會觸發其他堆疊環境的回流(Reflow)的喔~
昨天討論的瀏覽器的渲染步驟,其實還有最後一步:一個 Render Tree 經過計算後會轉換成許多堆疊環境,也可以理解成 圖層;我們先前聊過的「計算定位(Layout、Reflow)」、「繪製像素(Paint)」,這些步驟會發生在每一個圖層上,而瀏覽器會在最後的步驟「合成(Composite)」時,將這些圖層做疊加計算。
你可能會想問,為什麼不先疊加計算再繪製像素?
同樣的,是因為要讓各圖層的計算不會互相影響;如果某圖層只覆蓋到部分螢幕,當它樣式變動時,也只需要重算該圖層包含的部分畫面就好,不用全螢幕都重新繪製。
另外,堆疊環境也會影響到畫面的 z 軸排列順序。
回頭看一下剛剛提到的 z-index
定義,z-index
的影響範圍就只有在它所在的堆疊環境中;因此要確認兩元素的排列順序,必須先確認元素個別所在的堆疊環境順序,若在同一個堆疊環境,才比較兩者的 z-index
。
可以參考底下這個 MDN 的範例:
範例中的 #div1
、#div2
、#div3
是同層元素,共用了最外層的「根堆疊環境(Root Stacking Context)」,而 #div4
、#div5
、#div6
則是 #div3
的子元素。
由於 #div3
有設定 position: absolute
及 z-index: 3
,它會產生一個新的堆疊環境,即使 #div2
的 z-index
大於 #div5
的 z-index
,卻因為它們存在於不同的堆疊環境中,它們之間不會直接比較,而是從共用堆疊環境的 #div2
和 #div3
中 比較 z-index
,來決定 z 軸上的排列順序。
要建立一個新的堆疊環境非常容易,比較常用到的有以下幾種方式:
<html></html>
)position
設定成 fixed
或 sticky
position
設定成 relative
或 absolute
& 有設定 z-index
transform
屬性opacity
的值設定小於 1另外,開發者可以透過瀏覽器 DevTools 的 Layers 頁籤,觀察目前的頁面有哪些圖層:
如同前述,瀏覽器會將所有圖層做疊加運算;當圖層過多時也會稍微影響效能,在撰寫 CSS 時要稍微留心喔!
雖然聊了兩天的 CSS 中相對深入的主題,但對於瀏覽器渲染畫面這塊仍然只帶到皮毛;關於 Render Tree 轉換成堆疊環境的過程,讀者如果想要進一步探究的話,可以參考 這篇,但內容會偏離 CSS 太遠,這邊就不繼續深入了。
在研究這個主題時,突然發現很多以前覺得 CSS 玄妙的地方,好像都可以跟 Stacking Context 扯上關係;例如設定絕對定位時為什麼是參考外層的 positioned box 等等,真的有種被醍醐灌頂、打通任督二脈的感覺;果然在理解基本原理之後,許多難懂的知識點都可以迎刃而解!
聊了兩天的 CSS 明天就是 CSS 的最後一部啦!以上就是今天的 Stacking Context,如果本文有任何錯誤或不清楚的地方,都歡迎讀者您在底下留言回應!這場每天讓自己更好的旅程將會繼續下去,大家明天見囉~
筆者
Gary
半路出家網站工程師;半生熟的前端加上一點點的後端。
喜歡音樂,喜歡學習、分享,也喜歡當個遊戲宅。相信一切安排都是最好的路。